﻿//#define PIXELSTATS

using System;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security;
using System.Windows.Forms;
using OpenTK;
using OpenTK.Graphics.OpenGL;
using OpenTK.Input;
using RayDen.GLPlayground;
using RayDen.Library.Core;
using RayDen.Library.Entity.Interface;
using RayDen.RayEngine;
using PixelFormat = OpenTK.Graphics.OpenGL.PixelFormat;

namespace RayDen.GLPlayground
{

    public class TexturedQuadWindow : GameWindow
    {
        public string GetPicFileName()
        {
            return string.Format("{0}{1}", Path.GetFileName(config.FrameName), DateTime.UtcNow.Second);
            /*
            try {
                return DateTime.UtcNow.Ticks.ToString();
            }
            catch {
                Random rnd = new Random();
                return ((rnd.Next(1000) + 1) * 1000).ToString();
            }*/
        }

        public TexturedQuadWindow(IRenderConfig cfg)
            : base(cfg.Width, cfg.Height, new OpenTK.Graphics.GraphicsMode(32, 0, 0, 4))
        {
            config = cfg;
            Keyboard.KeyDown += delegate(object sender, KeyboardKeyEventArgs e)
            {
                if (e.Key == Key.Escape)
                {
                    this.Exit();
                }
                if (e.Key == Key.KeypadPlus)
                {
                    this.imageMode++;
                    if (imageMode > 2)
                    {
                        imageMode = 0;
                    }

                } if (e.Key == Key.KeypadMinus)
                {
                    this.imageMode--;
                    if (imageMode < 0)
                    {
                        imageMode = 2;
                    }
                }
                if (e.Key == Key.F1)
                {

                    this.config.SaveImage(config.SavePath + this.GetPicFileName() + ".png");
                }

                if (e.Key == Key.F5)
                {
                    this.config.SaveRawImage(config.SavePath + this.GetPicFileName() + ".exr");
                }

                if (e.Key == Key.Enter)
                {
                    (this.config as RayEngineConfiguration).ResetFilm();
                }

                if (e.Key == Key.F10)
                {
                    var eng = config as RayEngineConfiguration;
                    cfg.GetImagePlane().Reset();
                    eng.NextCamera();
                }

                if (e.Key == Key.F11)
                {
                    var eng = config as RayEngineConfiguration;
                    cfg.GetImagePlane().Reset();
                    eng.PrevCamera();
                }

                if (e.Key == Key.F12)
                {
                    cfg.GetImagePlane().Reset();
                }


                switch (e.Key)
                {
                    case Key.Number1:
                        config.RunCommand(1);
                        break;

                    case Key.Number2:
                        config.RunCommand(2);
                        break;
                    case Key.Number3:
                        config.RunCommand(3);
                        break;
                    case Key.Number4:
                        config.RunCommand(4);
                        break;
                    case Key.Number5:
                        config.RunCommand(5);
                        break;
                    case Key.Number6:
                        config.RunCommand(6);
                        break;
                    case Key.Number7:
                        config.RunCommand(7);
                        break;
                    case Key.Number8:
                        config.RunCommand(8);
                        break;
                    case Key.Number9:
                        config.RunCommand(9);
                        break;
                    case Key.Number0:
                        config.RunCommand(10);
                        break;
                }

                if ((e.Key == Key.AltLeft || e.Key == Key.AltRight) && (e.Key == Key.Enter || e.Key == Key.KeypadEnter))
                    if (this.WindowState == WindowState.Fullscreen)
                        this.WindowState = WindowState.Normal;
                    else
                        this.WindowState = WindowState.Fullscreen;
            };
        }

        private uint frameBuffer;

        protected override void OnClosed(EventArgs e)
        {
            GL.DeleteTexture(frameBuffer);
            config.Interrupt();
            base.OnClosed(e);
        }
        protected override void OnLoad(EventArgs e)
        {
            GL.ClearColor(Color.Black);
            GL.Enable(EnableCap.Texture2D);
            GL.GenTextures(1, out frameBuffer);
            GL.PixelStore(PixelStoreParameter.PackAlignment, 4);
            GL.BindTexture(TextureTarget.Texture2D, frameBuffer);
            pixels = Enumerable.Repeat(0f, Width * Height * 3).ToArray();
            OpenGLManager.LoadFromFloatArray(pixels, Width, Height, out frameBuffer);
            config.Start();
        }

        protected override void OnResize(EventArgs e)
        {
            GL.Viewport(0, 0, Width, Height);

            double aspect_ratio = Width / (double)Height;

            OpenTK.Matrix4 perspective = OpenTK.Matrix4.CreatePerspectiveFieldOfView(MathHelper.PiOver4, (float)aspect_ratio, 1, 64);
            GL.MatrixMode(MatrixMode.Projection);
            GL.LoadMatrix(ref perspective);

            Matrix4 lookat = Matrix4.LookAt(0, 0, 3, 0, 0, 0, 0, 1, 0);
            GL.MatrixMode(MatrixMode.Modelview);
            GL.LoadMatrix(ref lookat);

            base.OnResize(e);

        }

        public IRenderConfig config;

        private float[] pixels;
        //private int counter = 0;
        //private int updates = 10;

        private int imageMode = 0;
        IImagePlaneComponent film;
        float[] data;

        protected override void OnUpdateFrame(FrameEventArgs e)
        {
            //if (config is EthalonRenderConfig) {
            //    config.Start();
            //}
            base.OnUpdateFrame(e);


            film = config.GetImagePlane();
            {
                film.UpdateScreenBuffer();
                switch (imageMode)
                {
                    case 1:
                        data = (film as AdaptiveImageFilm).GetStatImage();
                        break;
                    case 2:
                        data = (film as AdaptiveImageFilm).GetVarianceImage();
                        break;
                        
                    default:
                        data = film.GetScreenBuffer();
                        break;
                }
                
                GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, Width, Height, PixelFormat.Rgb, PixelType.Float, data);
            }

            var rc = config as RayEngineConfiguration;
            if (rc != null)
                rc.CheckRestart();
        }



        protected override void OnRenderFrame(FrameEventArgs e)
        {

            if (pixels == null)
                return;
            GL.Clear(ClearBufferMask.ColorBufferBit);

            //film.UpdateScreenBuffer();


            GL.MatrixMode(MatrixMode.Projection);
            GL.PushMatrix();
            GL.LoadIdentity();
            GL.MatrixMode(MatrixMode.Modelview);
            GL.PushMatrix();
            GL.LoadIdentity();
            GL.Enable(EnableCap.Texture2D);
            GL.BindTexture(TextureTarget.Texture2D, frameBuffer);
            //var nonZero = pixels.Count(item => item > 0 && item < 255);
            //Console.WriteLine("{0} non zero non unit pixel values", nonZero);
//            GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgb8, Width, Height, 0, PixelFormat.Bgr, PixelType.UnsignedByte, pixels);

            //GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, Width, Height, PixelFormat.Rgb, PixelType.UnsignedByte, pixels);

            GL.Begin(BeginMode.Quads);
            GL.TexCoord2(0f, 0f);
            GL.Vertex2(-1f, -1f);
            GL.TexCoord2(0f, 1f);
            GL.Vertex2(-1f, 1f);
            GL.TexCoord2(1f, 1f);
            GL.Vertex2(1f, 1f);
            GL.TexCoord2(1f, 0f);
            GL.Vertex2(1f, -1f);
            GL.End();

            GL.MatrixMode(MatrixMode.Modelview);
            GL.PopMatrix();
            GL.MatrixMode(MatrixMode.Projection);
            GL.PopMatrix();
            GL.MatrixMode(MatrixMode.Modelview);
            /*
            GL.RasterPos2(0, 0);
            GL.DrawPixels(
                //config.GetImagePlane().Width,
                config.Width,
                config.Height,
                //config.GetImagePlane().Height, 
                PixelFormat.Rgb, PixelType.Float, pixels);*/
#if PIXELSTATS
            var anyNonBlack = pixels.Count(p => p > 0f);

            this.Title = //this.config.GetStats();
            anyNonBlack.ToString();
#else
            this.Title = this.config.GetStats();
#endif
            this.SwapBuffers();
        }


        public override void Exit()
        {
            GL.DeleteTexture(frameBuffer);
            this.config.Dispose();
            base.Exit();
        }

        protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
        {
            base.OnClosing(e);
            GL.DeleteTexture(frameBuffer);
            this.config.Dispose();
        }

    

    }

    




}

